/*
 * Event Commands
 */

package game.scene.map.event;
import dgo.interval.*;
import dgo.tilemap.*;
import dgo.MyLib;

import game.scene.map.Model;
import org.json.me.JSONArray;
import java.util.Stack;
import java.util.Vector;
import java.util.Hashtable;
import game.scene.SceneStack;

import dgo.Callback;
import dgo.SimpleInput;
import game.scene.map.WindowFactor;

public class EventCommands {
  public Model model;
  public Event rootEvent, event;
  public IntervalRunner eventRunner;
  private JSONArray _commands;
  private int _commandIndex;
  public boolean active;

  public EventCommands(Event rootEvent, Event event, JSONArray commands, Model model){
        this.model = model;
        this.rootEvent = rootEvent;
        this.event = event;
        _commandIndex = 0;
        eventRunner = new IntervalRunner();
        active = false;
        _commands = commands;
        reset();
  }

  public void update(SceneStack sceneStack, Stack commandStack){
    if(!eventRunner.isDone()){
      eventRunner.update();
      return;
    }
    if(command() == null || event.pauseCommand) return;
    
    try{
      String type;
      JSONArray command = null;
      
      while(active){
          event.pauseCommand = true;
          command = command();
          type = command.getString(0);
          //System.out.println(command);
          if(type.equals("if")){
            parseIf(command.getBoolean(1), command.getJSONArray(2));
            break;
          }
          if(type.equals("call_event_page")){
            Event t = event.getEvent(command.getint(1));
            commandStack.addElement(new EventCommands(rootEvent, t, ((EventPage)t.eventPages.elementAt(command.getint(2))).commands, model));
            nextCommand();
            break;
          }
          if(type.equals("color_change")){
            colorChange(command.getint(1), command.getint(2), command.getint(3), command.getint(4), command.getBoolean(5));
            nextCommand();
            break;
          }
          if(type.equals("route")){
            setRoute(command.getint(1), command.getBoolean(2), command.getBoolean(3), command.getBoolean(4), command.getJSONArray(5).getVector());
            break;
          }
          if(type.equals("message")){
            showMessage(command.getString(1), command.getint(2), command.getString(3), command.getint(4));
             break;
          }
          if(type.equals("self_switch")){
              event.selfSwitches[command.getint(1)] = command.getString(2).equals("on");
              nextCommand();
              continue;
          }
          if(type.equals("switch")){
              if(command.getString(1).equals("single")){
                event.setSwitch(command.getint(2), command.getString(3));
              }else{
                if(command.getString(1).equals("area")){
                  for(int i = command.getint(2); i <= command.getint(3); i++){
                    event.setSwitch(i, command.getString(4));
                  }
                }
              }

             nextCommand();
             continue;
          }
          if(type.equals("variable")){
            calculateVariable(command.getint(1), command.getString(2), command.getString(3), command.getint(4));
             nextCommand();
             continue;
          }
          if(type.equals("move_map")){
            sceneStack.pop();
            Hashtable h = new Hashtable();
            h.put("ep", EventParameters.cloneCharacterEventParameters(event.player()));
            h.put("map_id", command.getString(1));
            h.put("start_x", new Integer(command.getint(2)));
            h.put("start_y", new Integer(command.getint(3)));
            sceneStack.push(new game.scene.map.Scene(model.globalModel, h));
            break;
          }
          
          if(type.equals("move_scene")){
            sceneStack.pop();
            if(command.getString(1).equals("ending")){
              sceneStack.push(new game.scene.ending.Scene(model.globalModel));
            }
            break;
          }

          if(type.equals("wait")){
            setWait(command.getint(1));
            nextCommand();
            break;
          }
          
          if(type.equals("pause")){
            pause(command.getint(1), command.getString(2));
            break;
          }

          if(type.equals("play_bgm")){
            if(command.getString(1).equals("")){
              // stop bgm
              MyLib.stopBGM();
            }else{
              // play bgm
              MyLib.playBGM(getClass(), command.getString(1));
            }
            nextCommand();
            break;
          }
          
          if(type.equals("play_se")){
            if(command.getString(1).equals("")){
              // stop se
            }else{
              // play se
              MyLib.playSE(getClass(), command.getString(1));
            }
            nextCommand();
            break;
          }
           
          if(type.equals("goto")){
            gotoLabel(command.getint(1));
            continue;
          }

          if(type.equals("else")){
             gotoNextBlock("end");
             nextCommand();
             continue;
          }
          if(type.equals("end")){
             nextCommand();
             continue;
          }
          nextCommand();
        }
      }catch(Exception e){
        System.out.println("executeCommand Error" + e);
      }
    }

    private void colorChange(int r, int g, int b, int time, boolean wait){
      if(time == 0){
        model.globalModel.screenRed = r;
        model.globalModel.screenGreen = g;
        model.globalModel.screenBlue = b;
      }else{
        Callback changeRed = new Callback(this){ public void call(int value, Object argument){ model.globalModel.screenRed = value;}};
        Callback changeGreen = new Callback(this){ public void call(int value, Object argument){ model.globalModel.screenGreen = value;}};
        Callback changeBlue = new Callback(this){ public void call(int value, Object argument){ model.globalModel.screenBlue = value;}};
        model.tasks.addElement(new IntervalRunner(new Parallel(new Interval[]{
          new Lerp(time, model.globalModel.screenRed, r, changeRed),
          new Lerp(time, model.globalModel.screenGreen, g, changeGreen),
          new Lerp(time, model.globalModel.screenBlue, b, changeBlue)          
        })));
      }
      if(wait){ eventRunner.setInterval(new Act(time)); }
    }
    
      /* -------------------------------
       Pause Character
      ------------------------------- */
      private void pause(int eventID, String value){
        Event t = event.getEvent(eventID);
        
        t.pauseCommand = value.equals("on");
        if(eventID == 0){event.auto = false;} // Doesn't change the pause state after the event finished
      }
      
      public void setWait(int wait){
        eventRunner.setInterval(new Act(wait));
      }

      public void gotoNextBlock(String commandType){
        int depth = 0;
        String s = "";
        try{
          while(active){
            nextCommand();
            s = command().getString(0);
            if((depth == 0) && s.equals(commandType)){break;}
            if(s.equals("if")){depth += 1;}
            if(depth > 0 && s.equals("end")){depth -= 1;}
          }
        }catch(Exception e){
          System.out.println("gotoLabel Error" + e);
        }
      }

      public void gotoLabel(int labelNo){
        int i = 0;
        try{
          while(active){
            if(_commands.getJSONArray(i).getString(0).equals("label")){
            }
            if(_commands.getJSONArray(i).getString(0).equals("label") && _commands.getJSONArray(i).getint(1) == labelNo){
              _commandIndex = i;
              return;
            }
            i += 1;
            if(i >= _commands.length()){break;}
          }
        }catch(Exception e){
          System.out.println("gotoLabel Error" + e);
        }
        nextCommand();
      }
        
      public void parseIf(boolean elseStatement, JSONArray condition){
        if(!event.isConditionValid(condition)){
          if(elseStatement){
            gotoNextBlock("else");
          }else{
            gotoNextBlock("end");
          }
        }
        nextCommand();
      }

      /* ---------------------------------
       do variable calcularion
       ---------------------------------*/
      private void calculateVariable(int index, String operator, String operandType, int operand){
          int v = 0;
          if(operandType.equals("var")){
            v = model.globalModel.variables[operand];
          }else{
            if(operandType.equals("val")){
              v = operand;
            }
          }

          if(operator.equals("=")){
           model.globalModel.variables[index] = v;
          }else{
            if(operandType.equals("+")){
              model.globalModel.variables[index] += v;
            }else{
              if(operandType.equals("-")){
                model.globalModel.variables[index] -= v;
              }else{
                if(operandType.equals("*")){
                  model.globalModel.variables[index] *= v;
                }else{
                  if(operandType.equals("/")){
                    model.globalModel.variables[index] /= v;
                  }else{
                    if(operandType.equals("%")){
                      model.globalModel.variables[index] %= v;
                    }
                  } 
                } 
              } 
            }
          }
      }
      /* ---------------------------------
       Show Message
       ---------------------------------*/
      public void showMessage(String text, int characterID, String messageType, int autoClose){
        MapCharacter t = event.getCharacter(characterID);

        Callback func = new Callback(this){ public void call(int value, Object argument){
          Callback finish = new Callback(this){ public void call(int value, Object argument){ 
            WindowFactor obj = (WindowFactor)argument;
            EventCommands ec = obj.eventCommands;
            obj.finished = true;
            ec.nextCommand();
          }};
          
          WindowFactor obj = (WindowFactor)argument;
          
           if(obj.autoClose == -1){
             if(SimpleInput.isPressedNewly("ok")){
               obj.runner = new IntervalRunner(
                 new Sequence(new Interval[]{
                  new Act(1),
                  new Act(1, argument, finish)
                 })
               );
             }
           }else{
             obj.runner = new IntervalRunner(
               new Sequence(new Interval[]{
                new Act(1 + obj.autoClose),
                new Act(1, argument, finish)
               })
             );
           }
        }};

        model.windowManager.push(model.windowManager.createWindow(text, messageType), t, func, this, autoClose);
      }
      
      public void setRoute(int characterID, boolean routeSkip, boolean routeRepeat, boolean wait, Vector route){
        Event targetEvent = event.getEvent(characterID);
        MapCharacter character = targetEvent.character;
        targetEvent.saveRoute();
        targetEvent.parameters.routeRepeat = routeRepeat;
        targetEvent.parameters.routeSkip = routeSkip;
        targetEvent.route = route;
        targetEvent.routeIndex = 0;
        targetEvent.pauseMovement = false;
        if(!wait){ nextCommand();}
        
        Callback func = new Callback(this){ public boolean call(Object argument){
           boolean b = true;
           Event targetEvent = (Event)argument;
           MapCharacter character = targetEvent.character;
           if(!targetEvent.parameters.routeRepeat){
             if(targetEvent.routeIndex >= targetEvent.route.size() && !character.isRunning()){
               targetEvent.resetRoute();
               event.pauseMovement = true;
               nextCommand();
               b = false;
             }
           }
           return b;
        }};
        
        event.moveRunner = new IntervalRunner(new Pause(func, targetEvent));
      }
      
  // return curernt command
  public JSONArray command(){
    try{
      return _commands.getJSONArray(_commandIndex);
    }catch(Exception e){
      System.out.println("Command Error");
      return null;
    }
  }
   /*
    * Move to next command
    */
   private void nextCommand(){
     event.pauseCommand = false;
     _commandIndex += 1;
     if(_commandIndex >= _commands.length()){
       active = false;
     }
   }

   /*
    * Reset
    */
    public void reset(){
      _commandIndex = 0;
      active = true;
    }
}
